package Model;

import Jama.Matrix;
import Jama.EigenvalueDecomposition;
import org.apache.commons.math.stat.descriptive.DescriptiveStatistics;
import java.lang.System.*;
//import java.util.Iterator;

public class ACPMatrix{

	private int entite = 3;
	private int attribue = 4;
	private Matrix echantillon;
	private double[] poids;
	private Matrix reduit;
	private Matrix matrix_propre;
	private int[] index = {-1,-1,-1};
	private Matrix ecart_type;
	
	ACPMatrix( DataSet data,Clusterization clus){
		
		entite = data.getActionNbr();
		attribue = data.getNumericalAttributeNumber();
		//poids = new double[attribue];

		double[][] matrix = new double[entite+clus.getClusterNbr()][attribue];
        Attribute attr;
		
		for (int i=0 ; i < entite ; i++){
            for(int j=0;j<attribue;j++){
                attr=data.getNumericalAttribute(j);
                matrix[i][j] = (Float) data.getValue(i,attr,true); //true car on demande la valeur normalisée
            }
		}
        for (int i=0 ; i < clus.getClusterNbr() ; i++){
            for(int j=0;j<attribue;j++){
                attr=data.getNumericalAttribute(j);
                matrix[entite+i][j] = (Float) data.getValue(clus,i,attr,true); //true car on demande la valeur normalisée
            }
		}

        entite=entite+clus.getClusterNbr();
		echantillon = new Matrix(matrix);
		//echantillon.print(5, 5);

        /*
		int i = -1;
		Iterator it = kmeans.getWeightList().iterator();		
    	Weight weight ;	
    	String type ="o";
    	
    	while(it.hasNext())
    	{
    		i++;
            weight=(Weight) it.next();
            type = weight.getAttribute().getType();
          
            if ( type.equals("Numerical") )
            	poids[i] = (double)weight.getWeight();
            	//System.out.println(weight.getWeight());   
		}    
    	//System.out.println("i:" + i);
        */
	}
	
	ACPMatrix(int entite_n, int attribue_k, double[] poids, Matrix matrix){
	
		entite = entite_n;
		attribue = attribue_k;
		this.poids = poids;
		echantillon = matrix.copy();
		
	}
	
	ACPMatrix(int entite_n, int attribue_k, double[] poids, double[][] matrix){
		
		entite = entite_n;
		attribue = attribue_k;
		this.poids = poids;
		echantillon = new Matrix(matrix);
		
	}
	
	public void getEchantillon(){
		echantillon.print(5, 5);
	}
	
	public int getNombreEntite(){
		return entite;
	}
	
	public int getNombreAttr(){
		return attribue;
	}
	
	public DescriptiveStatistics des_colon( int nombre, int numero , Matrix matrix){
		
		DescriptiveStatistics des_manipuler = new DescriptiveStatistics(nombre);
		double temps;
		for (int i= 0; i<entite ; i++){
			temps = get_colon(nombre,numero,matrix).get(i,0);
			des_manipuler.addValue(temps);
		}
		return des_manipuler;
	}
	
	public Matrix get_colon( int nombre ,int numero, Matrix matrix ){
		
		int[] c={numero};
		Matrix ma_manipuler = new Matrix(1,1);
		ma_manipuler = (matrix.getMatrix(0,nombre-1,c)).copy();
		//ma_manipuler.print(5,5);
		return ma_manipuler;
	}
	
	public Matrix centre_gravite(){
	
		Matrix centre_g = new Matrix(1,attribue);
		Matrix ecart = new Matrix(1,attribue);
		DescriptiveStatistics descriptive;
		
		double temps;
		for(int i=0 ; i<attribue ; i++){
			descriptive = des_colon(entite,i,echantillon);
			temps = descriptive.getMean();
			centre_g.set(0, i, temps);
			temps = descriptive.getVariance();
			temps = Math.sqrt(temps);
			ecart.set(0,i,temps);
		}
		//centre_g.print(5,5);
		ecart_type = ecart.copy();
		//ecart_type.print(5, 5);
		return centre_g;
	}
	
	public void getCentreGravite(){
		centre_gravite().print(5, 5);
	}

	public Matrix matrix_poids(){
		// D : nxn
		Matrix m_poids = new Matrix(attribue,attribue);
		for(int i=0 ; i<attribue ; i++ ){
			m_poids.set(i, i, poids[i]);
		}
		//m_poids.print(5, 5);
		return m_poids;
	}
	
	public void getPoids(){
		matrix_poids().print(5, 5);
	}
	
	public void reduit(){
		//matrix M- : kxn 
		//matrix M- = M - g
		Matrix centre ;
		Matrix temps = new Matrix(entite,1);
		
		for(int i=0 ; i<entite; i++){
			temps.set(i, 0, 1);
		}
		centre = temps.times(centre_gravite());
		//matrix.print(5, 5);
		ecart_type = temps.times(ecart_type);
		//ecart_type.print(5, 5);
		
		centre = echantillon.minus(centre);
		//centre.print(5, 5);
		reduit = centre.arrayRightDivide(ecart_type).copy();
		//reduit.print(5, 5);
        System.out.println("on a reduit");
	}
	
	public void getReduit(){
		reduit.print(5, 5);
	}
	
	public Matrix variance_covariance(){
		//--- M' x M x D o� M : reduit ------ 
		Matrix matrix;

		//matrix = reduit.times(matrix_poids());
        matrix=reduit;
		matrix = reduit.transpose().times(matrix);
		//matrix.print(5, 5);
		return matrix;
	}
	
	public void getCovariance(){
		variance_covariance().print(5, 5);
	}
	
	public void matrix_propre(){

		Matrix matrix;
		Matrix D ;
		Matrix V;
		
		matrix = variance_covariance();
		//matrix.print(5,5);
        System.out.println("Var_covar OK");

		EigenvalueDecomposition diagonale ;
		diagonale = matrix.eig();
        System.out.println("eig OK");
		
		D = diagonale.getD();
		//D.print(5,5);
		indexVectPropre(D);
		V = diagonale.getV();
		//V.print(5,5);
		
		//A = V.times(D.times(V.transpose())); 
		//A.print(5,5);
		matrix_propre = V.copy();
	}
	
	public void getPropre(){
		matrix_propre.print(5, 5);
	}
	
	public void indexVectPropre( Matrix diagonal ){
		
		double max ;
		int temps;
		for (int i=0 ; i<3 ; i++)
		{
			max = -100;
			temps = -1;
        	for(int j=0 ; j<attribue && j != index[0] && j != index[1] ; j++)
        	{
        		if ( diagonal.get(j, j) > max )
        		{	
        			max = diagonal.get(j, j);
        			temps = j;
        		}
        	}
        	index[i] = temps;     
        	//System.out.println("index" + index[i]);
		}
	}
	
	public Matrix getEspaceDim1( int index_i ){
		
		Matrix vec_propre = new Matrix(attribue,1);
        Matrix echant;
        
        echant = reduit.copy();
		//echant.print(5, 5);
		
        if (index[index_i] != -1)
        	vec_propre= get_colon(attribue,index[index_i],matrix_propre);
     
        //vec_propre.print(5,5);
        echant = (echant.times(vec_propre));
        echant.print(5, 5); 
     
        return echant;
	}	
	
	public float[][] getEspaceDim3(){
		
		float[][] array = new float[entite][3];
		Matrix matrix = new Matrix(entite,3);
		
		for(int i = 0 ; i<3 ; i++)
		{
			int[] c={i};
			matrix.setMatrix(0,entite-1,c,getEspaceDim1(i));
		}
	
		for (int i=0 ; i<entite ; i++)
			for (int j=0 ; j<3 ; j++ )
				array[i][j] = (float)matrix.get(i, j);
		return array;
	}	
}
